part of "../animation.dart";

/// 需要注意的是，目前如果对图像进行了变幻，而Mask在变幻外，那么Mask本身是不会变化的
/// 要达到效果，应该将Mask放在比如Transform的里面
class LxMaskVFX extends StatefulWidget {
  /// 基于灰度图像对child进行遮罩
  final ImageProvider mask;
  final Widget child;

  /// 暂时scale需要冷加载才会起效
  final double scale;
  const LxMaskVFX({
    super.key,
    this.scale = 1,
    required this.mask,
    required this.child,
  });

  @override
  State<LxMaskVFX> createState() => _LxMaskVFXState();
}

class _LxMaskVFXState extends State<LxMaskVFX> {
  ImageShader? _shader;
  // 由于scale的运算会和图片有关，因此最佳的运算频率是有变化的时候重新运算
  // 出于这个角度，因此将scale保存下来，每次进行比较，当不同的时候才会重新运算
  late double scaleCache = widget.scale;

  @override
  void initState() {
    super.initState();
    _loadImage();
  }

  Future<void> _loadImage() async {
    // 将图像从句柄加载为Stream
    final ImageStream stream = widget.mask.resolve(ImageConfiguration.empty);

    // 当图像加载完毕的时候，触发completer
    stream.addListener(
      ImageStreamListener(
        (ImageInfo info, bool _) {
          _shader = ImageShader(
            info.image,
            TileMode.repeated, // 可以根据需要调整平铺模式
            TileMode.repeated,
            Matrix4.diagonal3Values(widget.scale, widget.scale, 1).storage,
          );
          WidgetsBinding.instance.addPostFrameCallback((_) {
            setState(() {});
          });
        },
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    if (widget.scale != scaleCache) {
      _loadImage();
      scaleCache = widget.scale;
    }

    return ExpandedShaderMask(
      shader: _shader ??
          ui.Gradient.linear(
            Offset.zero,
            const Offset(0, 0),
            [Colors.black, Colors.black],
          ),
      blendMode: BlendMode.modulate,
      child: widget.child,
    );
  }
}

/// 下面的代码由AI生成，我不知道原理，但是它可以解决遮罩层的尺寸问题，并且不影响child的尺寸
/// 比如说我的child是100*100，但是做过一些阴影特效，它超过了100*100，比如说是110*110，那么超出的这10个像素就不会应用这个mask遮罩
///
/// 注意：它的代价就是会缩放纹理本身的大小，如果纹理是随机可平铺的，那么这个方法非常合适
/// 但是如果遮罩层本身也是有精确
class ExpandedShaderMask extends SingleChildRenderObjectWidget {
  final Shader? shader;
  final BlendMode blendMode;

  const ExpandedShaderMask({
    super.key,
    required super.child,
    required this.shader,
    this.blendMode = BlendMode.modulate,
  });

  @override
  RenderObject createRenderObject(BuildContext context) =>
      _ExpandedShaderMaskRender(
        shader: shader,
        blendMode: blendMode,
      );

  @override
  void updateRenderObject(
      BuildContext context, _ExpandedShaderMaskRender renderObject) {
    renderObject
      ..shader = shader
      ..blendMode = blendMode;
  }
}

class _ExpandedShaderMaskRender extends RenderProxyBox {
  Shader? _shader;
  BlendMode _blendMode;

  _ExpandedShaderMaskRender({
    required Shader? shader,
    required BlendMode blendMode,
  })  : _shader = shader,
        _blendMode = blendMode;

  set shader(Shader? value) {
    if (_shader == value) return;
    _shader = value;
    markNeedsPaint();
  }

  set blendMode(BlendMode value) {
    if (_blendMode == value) return;
    _blendMode = value;
    markNeedsPaint();
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    if (child == null) return;

    // 关键步骤：创建扩展的绘制区域
    final expandedBounds = Rect.fromCenter(
      center: (offset & size).center,
      width: size.width * 1.3, // 30% 扩展，可根据阴影范围调整
      height: size.height * 1.3,
    );

    // 使用独立图层保证遮罩效果
    context.pushLayer(
      ShaderMaskLayer(
        shader: _shader,
        maskRect: expandedBounds,
        blendMode: _blendMode,
      ),
      super.paint,
      offset,
      childPaintBounds: expandedBounds, // 扩展绘制边界
    );
  }
}
